﻿using System;

namespace Sgr.Workspace.Models
{
    /// <summary>
    /// 审计日志概览视图模型
    /// </summary>
    public class AuditOverviewInfo
    {
        #region 常量定义

        private const int ARRAY_SIZE = 14;

        #endregion 常量定义

        #region 数据存储

        /// <summary>
        /// 近十四天，每天操作总数
        /// </summary>
        public int[] Totals { get; set; } = new int[ARRAY_SIZE];

        /// <summary>
        /// 近十四天，每天操作失败数
        /// </summary>
        public int[] Failures { get; set; } = new int[ARRAY_SIZE];

        #endregion 数据存储

        #region 核心方法

        /// <summary>
        /// 根据日期获取数组下标索引
        /// </summary>
        /// <param name="dateTime">目标日期</param>
        /// <returns>数组索引 (0-13)</returns>
        private static int GetIndex(DateTime dateTime)
        {
            int daysDiff = (dateTime.Date - Constant.UnixEpoch.Date).Days;
            return Math.Abs(daysDiff % ARRAY_SIZE);
        }

        /// <summary>
        /// 更新指定日期的数据
        /// </summary>
        /// <param name="dateTime">日期</param>
        /// <param name="total">操作总数</param>
        /// <param name="failures">失败数</param>
        public void UpdateData(DateTime dateTime, int total, int failures)
        {
            if (total < 0 || failures < 0 || failures > total)
                throw new ArgumentException("数据参数无效");

            int index = GetIndex(dateTime);
            Totals[index] = total;
            Failures[index] = failures;
        }

        /// <summary>
        /// 获取指定天数范围的统计数据
        /// </summary>
        /// <param name="array">要统计的数组</param>
        /// <param name="daysBack">从今天往前的天数</param>
        /// <param name="count">统计的天数</param>
        /// <returns>统计结果</returns>
        private static int GetRangeSum(int[] array, int daysBack, int count)
        {
            if (daysBack < 0 || count <= 0 || daysBack + count > ARRAY_SIZE)
                return 0;

            var today = DateTime.UtcNow.Date;
            int startIndex = GetIndex(today);
            int sum = 0;

            for (int i = daysBack; i < daysBack + count; i++)
            {
                int index = (startIndex - i - 1 + ARRAY_SIZE) % ARRAY_SIZE;
                sum += array[index];
            }

            return sum;
        }

        /// <summary>
        /// 获取最近指定天数的操作总数数组，索引0为最近一天
        /// </summary>
        /// <param name="days">天数（最多14天）</param>
        /// <returns>指定天数的操作总数数组，索引0为最近一天</returns>
        public int[] GetRecentTotalsArray(int days = 7)
        {
            if (days <= 0 || days > ARRAY_SIZE)
                days = 7;

            var today = DateTime.UtcNow.Date;
            int startIndex = GetIndex(today);
            int[] totalsArray = new int[days];

            for (int i = 0; i < days; i++)
            {
                int index = (startIndex - i - 1 + ARRAY_SIZE) % ARRAY_SIZE;
                totalsArray[i] = Totals[index];
            }

            return totalsArray;
        }

        /// <summary>
        /// 获取最近指定天数的操作失败数数组，索引0为最近一天
        /// </summary>
        /// <param name="days">天数（最多14天）</param>
        /// <returns>指定天数的操作失败数数组，索引0为最近一天</returns>
        public int[] GetRecentFailuresArray(int days = 7)
        {
            if (days <= 0 || days > ARRAY_SIZE)
                days = 7;

            var today = DateTime.UtcNow.Date;
            int startIndex = GetIndex(today);
            int[] failuresArray = new int[days];

            for (int i = 0; i < days; i++)
            {
                int index = (startIndex - i - 1 + ARRAY_SIZE) % ARRAY_SIZE;
                failuresArray[i] = Failures[index];
            }

            return failuresArray;
        }

        #endregion 核心方法

        #region 统计方法

        /// <summary>
        /// 获取近7天操作总数
        /// </summary>
        public int GetWeeklyTotal() => GetRangeSum(Totals, 0, 7);

        /// <summary>
        /// 获取近7天操作失败数
        /// </summary>
        public int GetWeeklyFailures() => GetRangeSum(Failures, 0, 7);

        /// <summary>
        /// 获取第二周操作总数（7-14天前）
        /// </summary>
        public int GetSecondWeekTotal() => GetRangeSum(Totals, 7, 7);

        /// <summary>
        /// 获取第二周操作失败数（7-14天前）
        /// </summary>
        public int GetSecondWeekFailures() => GetRangeSum(Failures, 7, 7);

        /// <summary>
        /// 获取近7天成功操作数
        /// </summary>
        public int GetWeeklySuccess() => GetWeeklyTotal() - GetWeeklyFailures();

        /// <summary>
        /// 获取第二周成功操作数
        /// </summary>
        public int GetSecondWeekSuccess() => GetSecondWeekTotal() - GetSecondWeekFailures();

        #endregion 统计方法

        #region 计算属性

        /// <summary>
        /// 近7天操作成功率（百分比）
        /// </summary>
        public double GetWeeklySuccessRate()
        {
            int total = GetWeeklyTotal();
            return total > 0
                ? Math.Round(GetWeeklySuccess() * 100.0 / total, 2)
                : 0;
        }

        /// <summary>
        /// 第二周操作成功率（百分比）
        /// </summary>
        public double GetSecondWeekSuccessRate()
        {
            int total = GetSecondWeekTotal();
            return total > 0
                ? Math.Round(GetSecondWeekSuccess() * 100.0 / total, 2)
                : 0;
        }

        /// <summary>
        /// 操作总数环比变化率（百分比）
        /// </summary>
        public double GetTotalGrowthRate()
        {
            int secondWeekTotal = GetSecondWeekTotal();
            if (secondWeekTotal == 0) return 0;

            int weeklyTotal = GetWeeklyTotal();
            return Math.Round((weeklyTotal - secondWeekTotal) * 100.0 / secondWeekTotal, 2);
        }

        /// <summary>
        /// 失败数环比变化率（百分比）
        /// </summary>
        public double GetFailureGrowthRate()
        {
            int secondWeekFailures = GetSecondWeekFailures();
            if (secondWeekFailures == 0) return 0;

            int weeklyFailures = GetWeeklyFailures();
            return Math.Round((weeklyFailures - secondWeekFailures) * 100.0 / secondWeekFailures, 2);
        }

        /// <summary>
        /// 成功率变化（百分点）
        /// </summary>
        public double GetSuccessRateChange()
        {
            return GetWeeklySuccessRate() - GetSecondWeekSuccessRate();
        }

        #endregion 计算属性

        #region 辅助方法

        /// <summary>
        /// 获取数组中有效数据的天数
        /// </summary>
        public int GetValidDataDays()
        {
            int count = 0;
            for (int i = 0; i < ARRAY_SIZE; i++)
            {
                if (Totals[i] > 0) count++;
            }
            return count;
        }

        /// <summary>
        /// 清空所有数据
        /// </summary>
        public void ClearData()
        {
            Array.Clear(Totals, 0, ARRAY_SIZE);
            Array.Clear(Failures, 0, ARRAY_SIZE);
        }

        #endregion 辅助方法
    }
}